package service

import (
	"database/sql"
	"errors"
	"fmt"
	"saas-app/app/dao"
	"saas-app/app/define"
	"saas-app/app/model"
	"saas-app/library/jwt"
	"time"

	"github.com/gogf/gf/frame/g"
	"github.com/gogf/gf/util/gconv"

	jwtgo "github.com/dgrijalva/jwt-go"
	"github.com/gogf/gf/crypto/gmd5"
)

type UserRepository interface {
	Login(passport string, password string) (token string)
	GetUserInfoByPassport(passport string) *model.User
	SignUp(param *define.SignUpParam) sql.Result
	CheckPassport(passport string) uint
	UserUpdate(id uint, req g.Map) error
	GetUserInfoById(id uint) *define.UserRoles
	Signout(userid uint) error
	CheckSchoolAdmin(school_id uint, user_id uint) bool
	GetCampusIdList(school_id uint, user_id uint) (campusIdList []uint)
}

type user struct{}

func UserService() UserRepository {
	return &user{}
}

/**
 * @description: 登录系统
 * @param {string} passport
 * @param {string} password
 * @return {*}
 */
func (u user) Login(passport string, password string) (token string) {

	if passport == "" || password == "" {
		panic("参数错误")
	}

	userInfo := UserService().GetUserInfoByPassport(passport)

	if userInfo == nil {
		panic("用户不存在")
	}

	if userInfo.Id == 0 {
		panic("用户不存在")
	}

	password = gmd5.MustEncrypt(password)
	if userInfo.Password != password {
		panic("账号或密码错误")
	}

	var claims jwt.CustomClaims
	claims.Username = userInfo.Passport
	claims.Userid = uint(userInfo.Id)
	claims.StandardClaims = jwtgo.StandardClaims{
		NotBefore: int64(time.Now().Unix() - 1000),        // 签名生效时间
		ExpiresAt: int64(time.Now().Unix() + 3600*24*365), // 过期时间 一小时
		Issuer:    jwt.GetSignKey(),                       //签名的发行者
	}

	mjwt := jwt.NewJWT()
	token = mjwt.CreateToken(claims)

	// 创建usertoken 1
	userToken := UserTokenService().GetUserTokenByUserId(uint(userInfo.Id))

	if userToken != nil {
		if userToken.Id == 0 {
			// 创建usertoken
			userToken.UserId = uint(userInfo.Id)
		}
		userToken.Token = token
	} else {
		userToken = &model.UserToken{}
		userToken.Token = token
		userToken.UserId = uint(userInfo.Id)
	}

	UserTokenService().SaveToken(userToken)

	return token
}

func (u user) GetUserInfoByPassport(passport string) *model.User {
	record, err := dao.User.FindOne("passport = ?", passport)
	userInfo := model.User{}
	record.Struct(&userInfo)
	if err != nil {
		panic(err)
	}
	return &userInfo
}

/**
 * @description: 用户注册
 * @param {*SignUpParam} param
 * @return {*}
 */
func (u user) SignUp(param *define.SignUpParam) sql.Result {
	// 昵称为非必需参数，默认使用账号名称
	if param.Nickname == "" {
		param.Nickname = param.Passport
	}
	// 账号唯一性数据检查
	if id := UserService().CheckPassport(param.Passport); id != 0 {
		panic(errors.New(fmt.Sprintf("账号 %s 已经存在", param.Passport)))
	}

	// 将输入参数赋值到数据库实体对象上
	var userInfo *model.User
	if err := gconv.Struct(param, &userInfo); err != nil {
		panic(err)
	}

	md5str := gmd5.MustEncrypt(userInfo.Password)
	userInfo.Password = md5str

	r, err := dao.User.Save(userInfo)

	if err != nil {
		panic(err)
	}

	return r
}

/**
 * @description: 检查账号是否存在
 * @param {string} passport
 * @return {*}
 */
func (u user) CheckPassport(passport string) uint {
	data := UserService().GetUserInfoByPassport(passport)
	if data == nil {
		return 0
	}
	return uint(data.Id)
}

/**
 * @description: 更新用户信息
 * @param {uint} id
 * @param {map[string]interface{}} reqMap
 * @return {*}
 */
func (u user) UserUpdate(id uint, req g.Map) error {
	_, err := dao.User.Update(req)
	return err
}

/**
 * @description: 获得用户信息详情
 * @param {uint} id
 * @return {*}
 */

func (u user) GetUserInfoById(id uint) *define.UserRoles {

	record, err := dao.User.LeftJoin("school_user", "user.id = school_user.user_id").Fields("user.*,school_user.campus_id, school_user.school_id").FindOne("user_id = ?", id)

	if err != nil {
		panic(err)
	}

	if record.IsEmpty() {
		panic("用户不存在")
	}

	user := &model.User{}

	if err := record.Struct(user); err != nil {
		panic(err)
	}

	userRole := define.UserRoles{}
	userRole.User = user

	campusId := record.GMap().Get("campus_id")
	identity := record.GMap().Get("identity")

	if campusId == 0 && identity == "school" {
		userRole.Roles = RoleService().GetAllPowerCode(user.Id)
	} else {
		roleIds := RoleService().GetUserRoleId(user.Id)
		if len(roleIds) > 0 {
			userRole.Roles = RoleService().GetPowerCodeByRoleId(roleIds)
		} else {
			panic("当前用户不在任何权限组")
		}
	}
	return &userRole
}

/**
 * @description: 退出
 * @param {uint} userid
 * @return {*}
 */
func (u user) Signout(userid uint) error {
	_, err := dao.UserToken.Delete("user_id", userid)
	return err
}

// 检查是否是学校管理员
func (u user) CheckSchoolAdmin(school_id uint, user_id uint) bool {

	record, err := dao.SchoolUser.Data(g.Map{"school_id": school_id, "user_id": "user_id", "identity": "school"}).FindOne()

	user := model.SchoolUser{}
	record.Struct(&user)

	if user.Id == 0 || err != nil || user.Id != user_id {
		return false
	}

	return true
}

// 获取所在校区id
func (u user) GetCampusIdList(school_id uint, user_id uint) (campusIdList []uint) {

	result, err := dao.SchoolUser.Where("school_id = ?", school_id).Where("user_id = ?", user_id).Where("identity = ?", "teacher").FindAll()

	schoolUsers := []model.SchoolUser{}
	result.Structs(&schoolUsers)

	if err != nil {
		return nil
	}

	for _, item := range schoolUsers {
		campusIdList = append(campusIdList, item.CampusId)
	}
	return campusIdList
}
